#include <iostream>
#include <functional>
#include <memory>
#include "TcpServer.hpp"
#include "Log.hpp"
#include "protocol.hpp"
#include "CalCulate.hpp"

using namespace protocol_ns;
using callback_t = std::function<Response(const Request &req)>;
class Service
{
public:
    Service(callback_t cb) : _cb(cb)
    {
    }

    void ServiceHelper(sock_sptr sockptr, InetAddr client)
    {

        int sockfd = sockptr->Sockfd();
        LOG(DEBUG, "get a new link, info %s:%d\n", client.Ip(), client.Port());

        std::string clientadddr = "[" + client.Ip() + ":" + std::to_string(client.Port()) + "]#";

        std::string inbuffer;
        while (true)
        {
            Request req;
            // 你怎么保证一个大的字符串里面有没有完整的请求
            // 1、
            int n = sockptr->Recv(&inbuffer);
            if (n < 0)
            {
                LOG(DEBUG, "client %s quit\n", clientadddr.c_str());
                break;
            }
            // 2、分析数据，确认完整报文
            std::string package = Decode(inbuffer);
            if (package.empty())
                continue;

            std::cout << "resq string:\n"
                      << package << std::endl;
            // 走到这里，一定能拿到一个完整的json串
            // 3、反序列化
            req.Deserialize(package);

            // 4、业务处理
            Response resp = _cb(req);

            // 5、对应答 做序列化
            std::string send_str;
            resp.Serialize(&send_str);

            std::cout << "resp Serialize:" << std::endl;

            // 6、添加长度报头
            send_str = Encode(send_str);

            //
            sockptr->Send(send_str); // 本次部队发送做处理
        }
        // 这个套接字，用完就必须关掉，因为这样才好给下一个申请连接用 不然可能导致->文件描述符泄露
        ::close(sockfd);
    }

private:
    callback_t _cb;
};

void Usage(std::string proc)
{
    std::cout << "Usage:\n\t" << proc << " local_port\n"
              << std::endl;
}

// ./tcpserver port
int main(int argc, char *argv[])
{
    if (argc != 2)
    {
        Usage(argv[0]);
        return 1;
    }
    EnableScreen();

    uint16_t port = std::stoi(argv[1]);
    CalCulate cal;
    Service calservice(std::bind(&CalCulate::Excute, &cal, std::placeholders::_1));
    io_service_t service = std::bind(&Service::ServiceHelper, &calservice, std::placeholders::_1, std::placeholders::_2);
    std::unique_ptr<TcpServer> tsvr = std::make_unique<TcpServer>(port, service);

    tsvr->Loop();

    return 0;
}
